Los patrones de creación son patrones que abstraen el proceso de instanciación, separando el sistema de cómo sus objetos son creados, encapsulando asé conocimientos sobre clases concretas usadas por el sistema.
Tienen como objetivo encapsular la creación de objetos.
Se utilizan para desvincular al sistema de la forma en que sus objetos son creados.
Abstract Factory: Permite trabajar con objetos de diferentes familias de manera que no se mezclen entre sí. De esa manera se consigue que el tipo de familia que se esté utilizando sea transparente.
Builder: Abstrae el proceso de creación de los objetos complejos, centralizándolo en un único punto.
Singleton: Garantiza que solo exista una instancia de un objeto y que la forma de acceder a dicha instancia sea general.
Permite crear familias de objetos relacionados sin especificar sus clases concretas.
Ejemplos:
“Temas” de interfaces gráficos, donde todos los elementos cambian a la vez (oscuro, claro, alto contraste...).
Gestión de bases de datos distintas donde la funcionalidad (conectar, acceder, cerrar) no bebería depender del tipo concreto.
Debemos utilizar este patrón cuando:
Un sistema debe ser independiente de cómo se crean sus productos.
Un sistema debe ser configurado con una familia de productos seleccionada entre varias familias.
Una familia de productos está diseñada para ser utilizada conjuntamente y es obligatorio cumplir esa restricción.
Ventajas e inconvenientes del patrón Abstract Factory:
Ventajas:
Proporciona flexibilidad ya que aísla a las clases concretas.
Facilita cambiar las familias de productos que se van a utilizar.
Inconvenientes:
Para agregar nuevos productos se deben modificar tanto las fábricas abstractas como las concretas.


xxxxxxxxxx51public interface FactoriaAccesoBD {2 3 public Conexion crearConexion();4 public Consulta crearConsulta();5}
xxxxxxxxxx51public interface Conexion {2
3 public boolean abrir();4 public boolean cerrar();5}xxxxxxxxxx51public interface Consulta {2
3 public boolean consultar();4 public boolean imprimir();5}
xxxxxxxxxx161public class ConexionMySQL implements Conexion {2 3 public ConexionMySQL() {4 System.out.println("Se ha creado el objeto ConexionMySQL");5 }6 7 public boolean abrir() {8 System.out.println("Se ha abierto una conexión en MySQL");9 return false;10 }11 12 public boolean cerrar() {13 System.out.println("Se ha cerrado una conexión en MySQL");14 return false;15 }16}xxxxxxxxxx161public class ConexionMongoDB implements Conexion {2 3 public ConexionMongoDB() {4 System.out.println("Se ha creado el objeto Conexion MongoDB");5 } 6 7 public boolean abrir() {8 System.out.println("Se ha abierto una conexión en MongoDB");9 return false;10 }11 12 public boolean cerrar() {13 System.out.println("Se ha cerrado una conexión en MongoDB");14 return false;15 }16}
xxxxxxxxxx161public class ConsultaMySQL implements Consulta {2 3 public ConsultaMySQL() {4 System.out.println("Se ha creado el objeto ConsultaMySQL");5 }6
7 public boolean consultar() {8 System.out.println("Consulta realizada en MySQL");9 return false;10 }11
12 public boolean imprimir() {13 System.out.println("Impresión realizada en MySQL");14 return false;15 }16}xxxxxxxxxx161public class ConsultaMongoDB implements Consulta {2
3 public ConsultaMongoDB() {4 System.out.println("Se ha creado el objeto ConsultaMongoDB");5 }6
7 public boolean consultar() {8 System.out.println("Consulta realizada en MongoDB");9 return false;10 }11
12 public boolean imprimir() {13 System.out.println("Impresión realizada en MongoDB");14 return false;15 }16}
xxxxxxxxxx141public class FactoriaMySQL implements FactoriaAccesoBD {2 3 public FactoriaMySQL() {4 System.out.println("Instanciada FactoriaMySQL");5 }6 7 public Conexion crearConexion() {8 return new ConexionMySQL();9 }10
11 public Consulta crearConsulta() {12 return new ConsultaMySQL();13 } 14}xxxxxxxxxx141public class FactoriaMongoDB implements FactoriaAccesoBD {2
3 public FactoriaMongoDB() {4 System.out.println("Instanciada FactoriaMongoDB");5 }6 7 public Conexion crearConexion() {8 return new ConexionMongoDB();9 }10
11 public Consulta crearConsulta() {12 return new ConsultaMongoDB();13 } 14}
xxxxxxxxxx381public class Aplicacion {2 3 // MANEJAMOS FACTORIAS Y OBJETOS ABSTRACTOS4 private FactoriaAccesoBD factoria;5 private Conexion conexion;6 private Consulta consulta;7 8 public Aplicacion(FactoriaAccesoBD factoria) {9 this.factoria=factoria;10 }11 12 public void crearConexion() {13 14 // DELEGAMOS LA CREACIÓN DE LA CONEXIÓN EN LA FACTORIA QUE TENGA15 conexion = factoria.crearConexion();16 // AQUÍ PODEMOS INVOCAR A LOS MÉTODOS DE CONEXION17 }18 19 public void crearConsulta() {20 21 // DELEGAMOS LA CREACIÓN DE LA CONSULTA EN LA FACTORIA QUE TENGA22 consulta = factoria.crearConsulta();23 // AQUÍ PODEMOS INVOCAR A LOS MÉTODOS DE CONSULTA24 }25
26 public static void main(String[] args) {27 28 // ES EN EL PROGRAMA PRINCIPAL DONDE SE DECIDE QUÉ FACTORIA CONCRETA SE USA EN CADA MOMENTO29 Aplicacion app = new Aplicacion(new FactoriaMongoDB());30 // Aplicacion app = new Aplicacion(new FactoriaMySQL());31 32 // UNA VEZ DECIDIDA LA FACTORIA CONCRETA, LA LÓGICA DE LA APLICACIÓN SE HACE A NIVEL DE OBJETOS ABSTRACTOS. 33 app.crearConexion();34 app.conexion.abrir();35 app.crearConsulta();36 app.consulta.imprimir();37 }38}
Builder es un patrón de diseño creacional que nos permite construir objetos complejos paso a paso.
Permite crear distintas representaciones usando el mismo método de construcción.
Este patrón lo podemos visualizar como una cadena de montaje destinada a la construcción de un objeto. En cada paso de la cadena se construye una parte del objeto.
Ejemplos:
Aplicación para generar archivos con distintos formatos.
Aplicación para construir ordenadores.
Se pueden tener ciertas variaciones del patrón, por ejemplo:
Un único constructor concreto.
Varios constructores concretos cuyos productos pertenecen a la misma jerarquía.
Varios constructores concretos cuyos productos no pertenecen a la misma jerarquía.
El objeto construido se recoge a través del director en lugar de directamente del constructor.
Ausencia de la clase directora (el cliente invoca de manera directa a los métodos del constructor).
Ventajas e inconvenientes del patrón Builder:
Ventajas:
Aísla la construcción del producto complejo.
Aumenta la modularidad del código al encapsular cómo se construyen objetos complejos.
Facilita cambiar la representación interna del producto.
Inconvenientes:
No tienen buena aplicación si las distintas partes del producto son muchas y las distintas representaciones no tienen alto solapamiento de partes.

El cliente crea un objeto director asociándole un constructor concreto.
El cliente solicita al director la construcción del producto.
El director construye el producto invocando a los métodos del constructor.
El constructor ejecuta sus métodos a medida que son invocados (generando el producto de manera incremental).
El cliente obtiene el producto del constructor.

xxxxxxxxxx71public interface ConstructorDocumento {2 3 public void iniciarDocumento();4 public void construirCabecera(String texto);5 public void construirCuerpo(String texto);6 public void construirPie(String texto);7}
xxxxxxxxxx311public class Documento {2 3 private String cabecera;4 private String cuerpo;5 private String pie;6 7 public void setCabecera(String cabecera) {8 this.cabecera = cabecera;9 }10 public void setCuerpo(String cuerpo) {11 this.cuerpo = cuerpo;12 }13 public void setPie(String pie) {14 this.pie = pie;15 } 16
17 // MÉTODO PARA PODER IMPRIMIR EL DOCUMENTO DE MANERA POLIMORFICA18 public String toString() {19 20 // CLASE QUE PERMITE COMPONER AÑADIENDO SOBRE LA MARCHA STRINGS21 StringBuilder sb = new StringBuilder();22 23 sb.append(cabecera);24 sb.append("\n");25 sb.append(cuerpo);26 sb.append("\n");27 sb.append(pie); 28 29 return sb.toString();30 } 31}
xxxxxxxxxx551public class ConstructorDocumentoHTML implements ConstructorDocumento {2 3 private Documento documento;4 5 public ConstructorDocumentoHTML() {6 System.out.println("Iniciada la construcción del documento HTML");7 }8 9 public void iniciarDocumento() {10 11 documento = new Documento();12 }13 14 public void construirCabecera(String texto) {15 16 // CONSTRUCCIÓN DE CABECERA17 StringBuilder sb = new StringBuilder();18 sb.append("<h1>");19 sb.append(texto);20 sb.append("</h1>");21
22 // QUE SE ASIGNA AL DOCUMENTO23 documento.setCabecera(sb.toString());24 }25
26 public void construirCuerpo(String texto) {27 28 // CONSTRUCCION DEL CUERPO29 StringBuilder sb = new StringBuilder();30 sb.append("<p>");31 sb.append(texto);32 sb.append("</p>");33
34 // QUE SE AÑADE AL DOCUMENTO35 documento.setCuerpo(sb.toString());36 }37
38 public void construirPie(String texto) {39 40 // CONSTRUCCIÓN DEL PIE41 StringBuilder sb = new StringBuilder();42 sb.append("<h5>");43 sb.append(texto);44 sb.append("<h5>");45
46 // QUE SE AÑADE AL DOCUMENTO47 documento.setPie(sb.toString());48 }49
50 public Documento obtenerDocumento() {51 52 // OBTENCIÓN DEL DOCUMENTO. SE MANTIENE FUERA POR COHERENCIA PARA CUANDO LOS OBJETOS NO SON DE LA MISMA JERARQUIA53 return documento;54 }55}
xxxxxxxxxx481public class ConstructorDocumentoJSON implements ConstructorDocumento{2 3 private Documento documento;4
5 public ConstructorDocumentoJSON() {6 System.out.println("Iniciada la construcción del documento JSON");7 }8 9 public void iniciarDocumento() {10 11 documento = new Documento();12 }13 14 public void construirCabecera(String texto) {15 16 StringBuilder sb = new StringBuilder();17 sb.append("{ cabecera: ");18 sb.append("\"" + texto + "\"");19 sb.append(",");20
21 documento.setCabecera(sb.toString());22 }23
24 public void construirCuerpo(String texto) {25 26 StringBuilder sb = new StringBuilder();27 sb.append("cuerpo: ");28 sb.append("\"" + texto + "\"");29 sb.append(",");30
31 documento.setCuerpo(sb.toString());32 }33
34 public void construirPie(String texto) {35 36 StringBuilder sb = new StringBuilder();37 sb.append("pie: ");38 sb.append("\"" + texto + "\"");39 sb.append("}");40
41 documento.setPie(sb.toString());42 }43 44 public Documento obtenerDocumento() {45 46 return documento;47 }48}
xxxxxxxxxx171public class Director {2 3 private ConstructorDocumento constructor;4
5 public Director(ConstructorDocumento constructor) {6
7 this.constructor = constructor;8 }9
10 public void construirDocumento(String cabecera, String cuerpo, String pie) {11 12 constructor.iniciarDocumento();13 constructor.construirCabecera(cabecera);14 constructor.construirCuerpo(cuerpo);15 constructor.construirPie(pie);16 } 17}
xxxxxxxxxx421package documentos;2
3public class Cliente {4 5 // TIENE UN DIRECTOR6 Director director;7 8 // PARA DOCUMENTO HTML9 //private ConstructorDocumentoHTML constructor;10 11 // PARA DOCUMENTO JSON12 private ConstructorDocumentoJSON constructor;13 14 // LAS PARTES DEL DOCUMENTO15 String cabecera = "Cabecera del documento";16 String cuerpo = "Cuerpo del documento";17 String pie = "Pie del documento";18 19 public Documento construirDocumento() {20 21 // NUEVO CONSTRUCTOR22 //constructor = new ConstructorDocumentoHTML();23 constructor = new ConstructorDocumentoJSON();24 25 // NUEVO DIRECTOR CON EL CONSTRUCTOR ADECUADO26 director = new Director(constructor);27 28 // SE SOLICITA AL DIRECTOR LA CONSTRUCCION DEL DOCUMENTO29 director.construirDocumento(cabecera, cuerpo, pie);30 31 // SE RECOGE EL DOCUMENTO DEL CONSTRUCTOR32 return constructor.obtenerDocumento();33 }34
35 public static void main(String[] args) {36 37 Cliente cliente = new Cliente();38 39 // SE CONSTRUYE EL OBJETO A TRAVÉS DEL MÉTODO CORRESPONDIENTE.40 System.out.println(cliente.construirDocumento());41 } 42}
Factory Method es un patrón de diseño creacional que proporciona una interface para crear objetos en una clase abstracta (superclase), mientras permite a las subclases alterar el tipo de objetos que se crearán.
La lógica se implementa a nivel de interface.
La creación se sobreescribe en los métodos de factoría concretos.
Los pasos elementales de la lógica se implementan en los productos concretos.
Aplicabilidad:
Una clase no puede prever la clase de objetos que debe crear.
Una clase quiere que sean sus subclases quienes especifiquen los objetos que ésta crea.
Ejemplos:
Una empresa de logística tras el éxito de su reparto con camiones decide ampliar a reparto por barco y urbano en bici.
Hasta ahora el modelo de negocio era, cada vez que se solicitaba un servicio:
Crear una tarea de transporte por camión.
Establecer una ruta con un número prefijado de puntos intermedios para ser realizado cada uno de ellos por un camión.
Iniciar la ruta informando de que puede realizarse seguimiento en la web.
Mediante un creador de transportes abstracto, el método de factoría desacoplará la lógica de negocio de la creación de los transportes.
Ventajas e inconvenientes del patrón Factory Method:
Ventajas:
Encapsula la creación de objetos (principio de responsabilidad única).
Permite desarrollar aplicaciones extensibles pudiendo añadir productos nuevos sin que la aplicación tenga que cambiar, basta con incorporar un nuevo creador concreto (principio abierto/cerrado).
Inconvenientes:
Número elevado de clases.
Factory Method vs Abstract Factory
Abstract Factory usa familias de productos mientras que Factory Method usa un solo producto.
La lógica de la aplicación de Abstract Factory está en el cliente, mientras que en Factory Method esta en la Factoría Abstracta a nivel de productos abstractos.


xxxxxxxxxx131public interface AFMLogistica {2 3 public MedioTransporteAbstracto crearTrasporte();4
5 public default void gestionarTrasporte(int numero) {6 7 MedioTransporteAbstracto transporte = crearTrasporte();8
9 transporte.display();10 transporte.estableceRuta(1, 9, 7, 6);11 transporte.iniciaRuta(1, 2, 9, 4);12 }13}
xxxxxxxxxx61public interface MedioTransporteAbstracto {2 3 public void display();4 public void estableceRuta(int coord_x_ini, int coord_y_ini, int coord_x_fin, int coord_y_fin);5 public void iniciaRuta(int coord_x_ini, int coord_y_ini, int coord_x_fin, int coord_y_fin);6}
xxxxxxxxxx261public class Bici implements MedioTransporteAbstracto{2
3 public Bici() {4 5 System.out.println("======> SOLICITADO REPARTO POR BICI");6 }7
8 public void display() {9 10 System.out.println("Display de la imagen con Bici");11 }12
13 public void estableceRuta(int coord_x_ini, int coord_y_ini, int coord_x_fin, int coord_y_fin) {14
15 System.out.printf("ESTABLECIENDO RUTA DE BICI de %d,%d a %d,%d\n",coord_x_ini, coord_y_ini, coord_x_fin, coord_y_fin);16 for (int i=0; i < 100; i++) System.out.print("c");17 System.out.println(); 18 }19
20 public void iniciaRuta(int coord_x_ini, int coord_y_ini, int coord_x_fin, int coord_y_fin) {21
22 System.out.printf("INICIANDO RUTA DE BICI de %d,%d a %d,%d\n",coord_x_ini, coord_y_ini, coord_x_fin, coord_y_fin);23 for (int i=0; i < 100; i++) System.out.print("C");24 System.out.println("CONSULTE EL ESTADO EN NUESTRA WEB"); 25 } 26}xxxxxxxxxx261public class Barco implements MedioTransporteAbstracto{2
3 public Barco() {4 5 System.out.println("======> SOLICITADO REPARTO POR BARCO");6 }7
8 public void display() {9 10 System.out.println("Display de la imagen con Barco");11 }12
13 public void estableceRuta(int coord_x_ini, int coord_y_ini, int coord_x_fin, int coord_y_fin) {14
15 System.out.printf("ESTABLECIENDO RUTA DE BARCO de %d,%d a %d,%d\n",coord_x_ini, coord_y_ini, coord_x_fin, coord_y_fin);16 for (int i=0; i < 100; i++) System.out.print("c");17 System.out.println(); 18 }19
20 public void iniciaRuta(int coord_x_ini, int coord_y_ini, int coord_x_fin, int coord_y_fin) {21
22 System.out.printf("INICIANDO RUTA DE BARCO de %d,%d a %d,%d\n",coord_x_ini, coord_y_ini, coord_x_fin, coord_y_fin);23 for (int i=0; i < 100; i++) System.out.print("C");24 System.out.println("CONSULTE EL ESTADO EN NUESTRA WEB"); 25 } 26}
xxxxxxxxxx121public class CFMLogisticaBici implements AFMLogistica{2 3 public CFMLogisticaBici() {4 5 System.out.println("Instanciado CFMLogisticaBici");6 }7 8 public MedioTransporteAbstracto crearTrasporte() {9 10 return new Bici();11 }12}xxxxxxxxxx121public class CFMLogisticaBarco implements AFMLogistica{2 3 public CFMLogisticaBarco() {4 5 System.out.println("Instanciado CFMLogisticaBarco");6 }7 8 public MedioTransporteAbstracto crearTrasporte() {9 10 return new Barco();11 }12}
xxxxxxxxxx281public class Cliente {2 3 // Primero creamos el objeto abstracto AFMLogistica para gestionar el transporte4 private AFMLogistica logistica;5 6 private void iniciarLogistica (String transporte) {7
8 if (transporte=="bici"){9 10 // Caso Bici11 logistica = new CFMLogisticaBici();12 logistica.gestionarTrasporte(2); 13 }14
15 if (transporte == "barco") {16 17 // Caso Barco18 logistica = new CFMLogisticaBarco();19 logistica.gestionarTrasporte(1);20 } 21 }22
23 public static void main(String[] args) {24 25 Cliente cliente = new Cliente();26 cliente.iniciarLogistica("bici");27 }28}